package com.nit.netty.bean.scanner;

import com.nit.netty.bean.NettyFactoryBean;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.filter.AnnotationTypeFilter;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Set;

/**
 * @Author: whb
 * @Description:
 * @CreateTime: 2020/8/21 10:33
 */
public class NettyClientInterfaceScanner extends ClassPathBeanDefinitionScanner {

    private NettyFactoryBean nettyFactoryBean = new NettyFactoryBean();

    private Class<? extends Annotation> annotationClass;

    public NettyClientInterfaceScanner(BeanDefinitionRegistry registry) {
        super(registry);
    }

    public void setAnnotationClass(Class<? extends Annotation> annotationClass) {
        this.annotationClass = annotationClass;
    }

    @Override
    public Set<BeanDefinitionHolder> doScan(String... basePackages) {
        // 由于注册了过滤器, 所以这里扫描出来的bean都是带有注解的
        Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);

        if (beanDefinitions.isEmpty()) {
            logger.warn("No netty interfaces was found in '"
                    + Arrays.toString(basePackages)
                    + "' package. Please check your configuration.");
        } else {
            // client需要被代理, 所以比server的多一步
            processBeanDefinitions(beanDefinitions);
        }

        return beanDefinitions;
    }

    // 注册过滤器, 过滤不含有annotationClass注解的类
    public void registerFilters() {
        boolean acceptAllInterfaces = true;

        if (this.annotationClass != null) {
            addIncludeFilter(new AnnotationTypeFilter(this.annotationClass));
            acceptAllInterfaces = false;
        }

        if (acceptAllInterfaces) {
            addIncludeFilter((metadataReader, metadataReaderFactory) -> true);
        }

        // exclude package-info.java
        addExcludeFilter((metadataReader, metadataReaderFactory) -> {

            String className = metadataReader.getClassMetadata()
                    .getClassName();
            return className.endsWith("package-info");
        });
    }

    /**
    * @Description: 将生成该类的bean工厂设置为NettyBeanFactory
    */
    private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {

        GenericBeanDefinition definition;

        for (BeanDefinitionHolder holder : beanDefinitions) {

            definition = (GenericBeanDefinition) holder.getBeanDefinition();
            definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName());
            // bean信息中设置bean工厂为我们自定义的bean工厂
            definition.setBeanClass(this.nettyFactoryBean.getClass());

            definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
        }
    }

    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
    }

    @Override
    protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
        return metadataReader.getClassMetadata().isInterface() && metadataReader.getClassMetadata().isIndependent();
    }

    public void setNettyFactoryBean(NettyFactoryBean instantiateClass) {
        this.nettyFactoryBean = instantiateClass != null ? instantiateClass : this.nettyFactoryBean;
    }
}
